﻿using System.Collections.Generic;
using System.Windows.Forms;
using ATEC.ATDataCoreNET.ATObjects;

/// <summary>
/// 类名：UsingSharedOUnitMethods
/// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象
/// 功能：展示如何创建和管理共享组（SharedOUnit）对象，包括创建定义、实例化和属性修改等操作。
/// 关键类及说明：
///     - SharedOUnitDefObject：共享组定义对象，用于创建可重用的对象组合。
///     - SharedOUnitObject：共享组实例对象，基于定义创建的具体实例。
///     - ATObject：平台对象基类，用于表示各种几何实体。
///     - ObjectPropertiesSetter：对象属性设置器，用于修改对象的颜色等属性。
/// </summary>
namespace SharedOUnitExample
{ 
    public class UsingSharedOUnitMethods
    {
        private static uint LampCount = 200;

        /// <summary>
        /// 方法名：GetLampParts
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/几何创建
        /// 功能：创建路灯模型的几何部件，包括底座、灯杆和五个灯泡组件。
        /// 参数：
        ///     - ptOri：ATEC.GeometryNET.XPoint3d，路灯的原点位置
        /// 返回值：List<ATObject>，包含所有组成路灯的几何对象的列表
        /// 关键类及说明：
        ///     - ATConeDetail：圆锥体详细信息，用于创建底座和灯杆
        ///     - ATSphereDetail：球体详细信息，用于创建灯泡
        ///     - BaseSolid：基础实体类，用于创建三维几何体
        /// </summary>
        public static List<ATObject> GetLampParts(ATEC.GeometryNET.XPoint3d ptOri)
        {
            List<ATObject> arr = new List<ATObject>();
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();

            ATEC.ATDataCoreNET.ObjectPropertiesSetter setter = new ATEC.ATDataCoreNET.ObjectPropertiesSetter();
            setter.SetColor(2);

            double seatH = 5000.0;
            double bodyH = 40000.0;

            //底座
            ATEC.GeometryNET.ATConeDetail seatDetail = new ATEC.GeometryNET.ATConeDetail(
                ptOri,
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * seatH,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                2000,
                1000,
                true);

            ATEC.GeometryNET.BaseSolid seatSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(seatDetail);
            ATEC.ATDataCoreNET.SolidCoreEntity seatEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out seatEnt, seatSolid, scenR);
            var seatObj = GeometryToATObject.ToObject(scenR.GetATScene(), seatEnt, null);
            setter.Apply(seatObj);
            arr.Add(seatObj);

            //灯杆
            ATEC.GeometryNET.ATConeDetail poleDetail = new ATEC.GeometryNET.ATConeDetail(
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * seatH,
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * (seatH + bodyH),
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                800,
                800,
                true);

            ATEC.GeometryNET.BaseSolid poleSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(poleDetail);
            ATEC.ATDataCoreNET.SolidCoreEntity poleEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out poleEnt, poleSolid, scenR);
            var poleObj = GeometryToATObject.ToObject(scenR.GetATScene(), poleEnt, null);
            setter.Apply(poleObj);
            arr.Add(poleObj);

            ATEC.GeometryNET.XPoint3d ptPoleCen = new ATEC.GeometryNET.XPoint3d(ptOri);
            ptPoleCen.Z += (bodyH + seatH);
            setter.SetColor(4);

            //灯泡 和 灯泡杆子
            for (int i = 0; i < 5; ++i)
            {
                ATEC.GeometryNET.XPoint3d ptSphereCen = new ATEC.GeometryNET.XPoint3d(ptPoleCen);
                ATEC.GeometryNET.ATConeDetail minorPoleDetail;

                if (i == 0)
                {
                    ptSphereCen.Z += seatH;
                    minorPoleDetail = new ATEC.GeometryNET.ATConeDetail(ptPoleCen,
                        ptSphereCen,
                        ATEC.GeometryNET.XVector3d.UnitX,
                        ATEC.GeometryNET.XVector3d.UnitY,
                        100.0,
                        100.0,
                        true);
                }
                else if (i == 1)
                {
                    ptSphereCen.X += 1.6 * seatH;
                    minorPoleDetail = new ATEC.GeometryNET.ATConeDetail(ptPoleCen,
                        ptSphereCen,
                        ATEC.GeometryNET.XVector3d.UnitZ,
                        ATEC.GeometryNET.XVector3d.UnitY,
                        100.0,
                        100.0,
                        true);
                }
                else if (i == 2)
                {
                    ptSphereCen.Y += 1.6 * seatH;
                    minorPoleDetail = new ATEC.GeometryNET.ATConeDetail(ptPoleCen,
                        ptSphereCen,
                        ATEC.GeometryNET.XVector3d.UnitZ,
                        ATEC.GeometryNET.XVector3d.UnitX,
                        100.0,
                        100.0,
                        true);
                }
                else if (i == 3)
                {
                    ptSphereCen.X -= 1.6 * seatH;
                    minorPoleDetail = new ATEC.GeometryNET.ATConeDetail(ptPoleCen,
                        ptSphereCen,
                        ATEC.GeometryNET.XVector3d.UnitZ,
                        ATEC.GeometryNET.XVector3d.UnitY,
                        100.0,
                        100.0,
                        true);
                }
                else
                {
                    ptSphereCen.Y -= 1.6 * seatH;
                    minorPoleDetail = new ATEC.GeometryNET.ATConeDetail(ptPoleCen,
                        ptSphereCen,
                        ATEC.GeometryNET.XVector3d.UnitZ,
                        ATEC.GeometryNET.XVector3d.UnitX,
                        100.0,
                        100.0,
                        true);
                }

                ATEC.GeometryNET.ATSphereDetail bulbDetail = new ATEC.GeometryNET.ATSphereDetail(ptSphereCen, 1200.0);
                ATEC.GeometryNET.BaseSolid bulbSolid = ATEC.GeometryNET.BaseSolid.CreateATSphere(bulbDetail);

                ATEC.ATDataCoreNET.SolidCoreEntity bulbEnt = null;
                SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out bulbEnt, bulbSolid, scenR);

                var bulbObj = GeometryToATObject.ToObject(scenR.GetATScene(), bulbEnt, null);
                if ( bulbObj != null)
                {
                    setter.Apply(bulbObj);
                    arr.Add(bulbObj);
                }

                ATEC.GeometryNET.BaseSolid minorPoleSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(minorPoleDetail);
                ATEC.ATDataCoreNET.SolidCoreEntity minorPoleEnt = null;
                SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out minorPoleEnt, minorPoleSolid, scenR);
                var minorPoleObj = GeometryToATObject.ToObject(scenR.GetATScene(), minorPoleEnt, null);

                if (minorPoleObj != null)
                {
                    setter.Apply(minorPoleObj);
                    arr.Add(minorPoleObj);
                }
            }
            return arr;
        }

        /// <summary>
        /// 方法名：GetLightParts
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/几何创建
        /// 功能：创建另一种样式路灯模型的几何部件，包括底座、主灯杆和三个横向灯具。
        /// 参数：
        ///     - ptOri：ATEC.GeometryNET.XPoint3d，路灯的原点位置
        /// 返回值：List<ATObject>，包含所有组成路灯的几何对象的列表
        /// </summary>
        public static List<ATObject> GetLightParts(ATEC.GeometryNET.XPoint3d ptOri)
        {
            List<ATObject> arr = new List<ATObject>();
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();

            ATEC.ATDataCoreNET.ObjectPropertiesSetter setter = new ATEC.ATDataCoreNET.ObjectPropertiesSetter();
            setter.SetColor(2);

            double seatH = 5000.0;
            double bodyH = 40000.0;

            //底座
            ATEC.GeometryNET.ATConeDetail seatDetail = new ATEC.GeometryNET.ATConeDetail(
                ptOri,
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * seatH,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                2000,
                1000,
                true);

            ATEC.GeometryNET.BaseSolid seatSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(seatDetail);
            ATEC.ATDataCoreNET.SolidCoreEntity seatEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out seatEnt, seatSolid, scenR);
            var seatObj = GeometryToATObject.ToObject(scenR.GetATScene(), seatEnt, null);
            setter.Apply(seatObj);
            arr.Add(seatObj);

            //灯杆
            ATEC.GeometryNET.ATConeDetail poleDetail = new ATEC.GeometryNET.ATConeDetail(
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * seatH,
                ptOri + ATEC.GeometryNET.XVector3d.UnitZ * (seatH + bodyH),
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                800,
                800,
                true);

            ATEC.GeometryNET.BaseSolid poleSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(poleDetail);
            ATEC.ATDataCoreNET.SolidCoreEntity poleEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out poleEnt, poleSolid, scenR);
            var poleObj = GeometryToATObject.ToObject(scenR.GetATScene(), poleEnt, null);
            setter.Apply(poleObj);
            arr.Add(poleObj);

            ATEC.GeometryNET.XPoint3d ptPoleCen = new ATEC.GeometryNET.XPoint3d(ptOri);
            ptPoleCen.Z += (bodyH + seatH);
            setter.SetColor(4);

            ATEC.GeometryNET.ATConeDetail upperPoleDetail = new ATEC.GeometryNET.ATConeDetail(
                ptPoleCen + 7 * seatH * ATEC.GeometryNET.XVector3d.UnitY,
                ptPoleCen - seatH * ATEC.GeometryNET.XVector3d.UnitY,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitZ,
                150.0,
                150.0,
                true);

            ATEC.GeometryNET.BaseSolid upperPoleSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(upperPoleDetail);
            ATEC.ATDataCoreNET.SolidCoreEntity upperPoleEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out upperPoleEnt, upperPoleSolid, scenR);
            var upperPoleObj = GeometryToATObject.ToObject(scenR.GetATScene(), upperPoleEnt, null);
            setter.Apply(upperPoleObj);
            arr.Add(upperPoleObj);

            ATEC.GeometryNET.ATConeDetail firstLightDetail = new ATEC.GeometryNET.ATConeDetail(
                ptPoleCen + 2 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 75 * ATEC.GeometryNET.XVector3d.UnitZ,
                ptPoleCen + 2 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 500*ATEC.GeometryNET.XVector3d.UnitZ,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                400.0,
                800.0,
                true);

            ATEC.GeometryNET.BaseSolid firstLightSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(firstLightDetail);
            
            ATEC.ATDataCoreNET.SolidCoreEntity firstLightEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out firstLightEnt, firstLightSolid, scenR);

            var firstLightObj = GeometryToATObject.ToObject(scenR.GetATScene(), firstLightEnt, null);
            if (firstLightObj != null)
            {
                setter.Apply(firstLightObj);
                arr.Add(firstLightObj);
            }

            ATEC.GeometryNET.ATConeDetail secondLightDetail = new ATEC.GeometryNET.ATConeDetail(
                ptPoleCen + 4.0 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 75 * ATEC.GeometryNET.XVector3d.UnitZ,
                ptPoleCen + 4.0 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 500 * ATEC.GeometryNET.XVector3d.UnitZ,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                400.0,
                800.0,
                true);

            ATEC.GeometryNET.BaseSolid secondLightSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(secondLightDetail);

            ATEC.ATDataCoreNET.SolidCoreEntity secondLightEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out secondLightEnt, secondLightSolid, scenR);

            var secondLightObj = GeometryToATObject.ToObject(scenR.GetATScene(), secondLightEnt, null);
            if (secondLightObj != null)
            {
                setter.Apply(secondLightObj);
                arr.Add(secondLightObj);
            }

            ATEC.GeometryNET.ATConeDetail thirdLightDetail = new ATEC.GeometryNET.ATConeDetail(
                ptPoleCen + 6 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 75 * ATEC.GeometryNET.XVector3d.UnitZ,
                ptPoleCen + 6 * seatH * ATEC.GeometryNET.XVector3d.UnitY - 500 * ATEC.GeometryNET.XVector3d.UnitZ,
                ATEC.GeometryNET.XVector3d.UnitX,
                ATEC.GeometryNET.XVector3d.UnitY,
                400.0,
                800.0,
                true);

            ATEC.GeometryNET.BaseSolid thirdLightSolid = ATEC.GeometryNET.BaseSolid.CreateATCone(thirdLightDetail);

            ATEC.ATDataCoreNET.SolidCoreEntity thirdLightEnt = null;
            SSDPNET.DataCore.EntityUtl.Create.EntityFromBaseSolid(out thirdLightEnt, thirdLightSolid, scenR);

            var thirdLightObj = GeometryToATObject.ToObject(scenR.GetATScene(), thirdLightEnt, null);
            if (thirdLightObj != null)
            {
                setter.Apply(thirdLightObj);
                arr.Add(thirdLightObj);
            }
            return arr;
        }

        /// <summary>
        /// 方法名：SharedOUnitCreateDefinition
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/定义
        /// 功能：创建名为"StreetLamp"的共享组定义，将路灯的所有部件组合成一个可重用的定义。
        /// 参数：无
        /// 返回值：无
        /// 关键类及说明：
        ///     - SharedOUnitDefObject：共享组定义对象，用于创建可重用的对象组合
        /// </summary>
        public static void SharedOUnitCreateDefinition()
        {
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();

            //创建一个共享组的定义
            ATEC.ATDataCoreNET.ATObjects.SharedOUnitDefObject scEeh = new ATEC.ATDataCoreNET.ATObjects.SharedOUnitDefObject(scenR.GetATScene(), "StreetLamp");
            var parts = GetLampParts(ATEC.GeometryNET.XPoint3d.Zero);

            foreach( var onePart in parts)
            {
                scEeh.AddChildObject(onePart);
            }

            scEeh.AddChildComplete();
            if ( scEeh.AddToScene() == ATEC.ATDataCoreNET.StatusInt.Success)
            {
                System.Windows.Forms.MessageBox.Show("成功创建名为StreetLamp的共享组定义");
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("名为StreetLamp的共享组定义已存在");
            }
        }

        /// <summary>
        /// 方法名：SharedOUnitCreateInstances
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/实例化
        /// 功能：基于"StreetLamp"定义批量创建共享组实例，并测量创建时间。
        /// 参数：无
        /// 返回值：无
        /// 说明：
        ///     使用共享组方式批量创建对象，可以提高效率和减少内存占用。
        ///     方法会在X轴方向上等间距创建指定数量的路灯实例。
        /// </summary>
        public static void SharedOUnitCreateInstances()
        {
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();
            System.DateTime dtBegin = System.DateTime.Now;
            for (uint i = 0; i < LampCount; ++i)
            {
                //Create named Cell instances.
                ATEC.GeometryNET.XPoint3d origin1 = new ATEC.GeometryNET.XPoint3d(100000 * i, 0, 0);
                ATEC.GeometryNET.XPoint3d scale = new ATEC.GeometryNET.XPoint3d(1, 1, 1);
                ATEC.GeometryNET.XMatrix3d rotation = new ATEC.GeometryNET.XMatrix3d(1, 0, 0, 0, 1, 0, 0, 0, 1);
                ATEC.ATDataCoreNET.ATObjects.SharedOUnitObject sharedInstanceEeh = new ATEC.ATDataCoreNET.ATObjects.SharedOUnitObject(scenR.GetATScene(), null, "StreetLamp", origin1, rotation, scale);

                ATEC.ATDataCoreNET.TransformInfo transformInfo = new ATEC.ATDataCoreNET.TransformInfo(ATEC.GeometryNET.XTransform3d.Identity);
                sharedInstanceEeh.ApplyTransform(transformInfo);
                sharedInstanceEeh.AddToScene();
            }

            System.DateTime dtEnd = System.DateTime.Now;
            System.TimeSpan dtTime = dtEnd - dtBegin;
            System.Windows.Forms.MessageBox.Show($"共享组的方式耗时{dtTime.Milliseconds}毫秒");
        }

        /// <summary>
        /// 方法名：SharedOUnitCreateSolids
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/对比测试
        /// 功能：使用普通方式（逐个创建实体）创建相同数量的路灯模型，用于与共享组方式性能对比。
        /// 参数：无
        /// 返回值：无
        /// 说明：
        ///     此方法用于对比传统创建方式与共享组方式的性能差异。
        ///     在Y=200000位置的X轴方向上创建路灯。
        /// </summary>
        public static void SharedOUnitCreateSolids()
        {
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();
            System.DateTime dtBegin = System.DateTime.Now;

            for (uint i = 0; i < LampCount; ++i)
            {
                //Create named Cell instances.
                ATEC.GeometryNET.XPoint3d origin1 = new ATEC.GeometryNET.XPoint3d(100000 * i, 200000, 0);
                var parts = GetLampParts(origin1);

                foreach (var onePart in parts)
                {
                    onePart.AddToScene();
                }
            }

            System.DateTime dtEnd = System.DateTime.Now;
            System.TimeSpan dtTime = dtEnd - dtBegin;
            System.Windows.Forms.MessageBox.Show($"一个一个solid创建的方式耗时{dtTime.Milliseconds}毫秒");
        }

        /// <summary>
        /// 方法名：ModifyTheDefinition
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/定义修改
        /// 功能：修改已存在的"StreetLamp"共享组定义，将其更新为新的路灯样式。
        /// 参数：无
        /// 返回值：无
        /// 关键类及说明：
        ///     - ObjectSelectSet：对象选择集，用于存储要更新的几何对象
        ///     - SharedOUnitDefExtension：共享组定义扩展类，提供定义修改功能
        /// </summary>
        public static void ModifyTheDefinition()
        {
            ATEC.ATDataCoreNET.ObjectPropertiesSetter setter = new ATEC.ATDataCoreNET.ObjectPropertiesSetter();
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();

            var parts = GetLightParts(ATEC.GeometryNET.XPoint3d.Zero);
            ATEC.ATDataCoreNET.ObjectSelectSet sets=new ATEC.ATDataCoreNET.ObjectSelectSet();
            foreach (var onePart in parts)
            {
                sets.Insert(onePart, false);
            }
            SSDPNET.DataCore.SharedOUnitDefExtension.ModifySharedOUnitDefObject("StreetLamp", sets, true, scenR.GetATProject());
            return;
        }

        /// <summary>
        /// 方法名：SharedOUnitOverideInstanceColor
        /// 分类：玄镜BIM图形平台/C#开发/示例代码/共享组对象/实例属性
        /// 功能：创建三个放大的路灯实例，并为每个实例设置不同的颜色覆盖值。
        /// 参数：无
        /// 返回值：无
        /// 说明：
        ///     演示如何在不修改共享组定义的情况下，
        ///     通过SharedOUnitOverrides为个别实例设置特殊的显示属性。
        /// </summary>
        public static void SharedOUnitOverideInstanceColor()
        {
            ATEC.ATDataCoreNET.ObjectPropertiesSetter setter = new ATEC.ATDataCoreNET.ObjectPropertiesSetter();
            ATEC.ATDataCoreNET.ATSceneRef scenR = SSDPNET.ScenesFunctions.SceneRefGetActive();
            for (uint i = 0; i < 3; ++i)
            {
                //Create named Cell instances.
                ATEC.GeometryNET.XPoint3d origin1 = new ATEC.GeometryNET.XPoint3d(100000 * i, 400000, 0);
                ATEC.GeometryNET.XPoint3d scale = new ATEC.GeometryNET.XPoint3d(3, 3, 3);
                ATEC.GeometryNET.XMatrix3d rotation = new ATEC.GeometryNET.XMatrix3d(1, 0, 0, 0, 1, 0, 0, 0, 1);
                ATEC.ATDataCoreNET.ATObjects.SharedOUnitObject sharedInstanceEeh = new ATEC.ATDataCoreNET.ATObjects.SharedOUnitObject(scenR.GetATScene(), null, "StreetLamp", origin1, rotation, scale);

                ATEC.ATDataCoreNET.TransformInfo transformInfo = new ATEC.ATDataCoreNET.TransformInfo(ATEC.GeometryNET.XTransform3d.Identity);
                sharedInstanceEeh.ApplyTransform(transformInfo);

                var sharedOUnitOverFlag = sharedInstanceEeh.SharedOUnitOverrides;
                sharedOUnitOverFlag.Color = true;
                sharedInstanceEeh.SharedOUnitOverrides = sharedOUnitOverFlag;

                setter.SetColor(i);
                setter.Apply(sharedInstanceEeh);

                sharedInstanceEeh.AddToScene();
            }
        }
    }
}